Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Several updates to ValueTask #16098

Merged
merged 4 commits into from
Jan 30, 2018
Merged

Conversation

stephentoub
Copy link
Member

Make ValueTask code more easily shared with corefx

  • Remove superfluous use of tuples that cause complications with corefx's netstandard1.0 build
  • Move CoreCLR-specific API usage into a partial struct

With those changes, we'll be able to fully share the ValueTask code and associated CompilerServices code, other than the three methods in the .CoreCLR.cs file, and can delete corefx's duplicate implementation.

Make ValueTask awaiters readonly structs

  • They previously weren't flagged because they had a non-readonly field. That field is the wrapped ValueTask, and it wasn't readonly because doing so would have resulted in copies being made when invoking methods on ValueTask. But now that ValueTask itself is readonly, we can make the field and then the struct readonly.

Remove defunct CreateAsyncMethodBuilder method

  • This is a holdover from a beta release of a C# compiler. It's not needed, and we agreed in API review that even though it did ship in the ref for the System.Threading.Tasks.Extensions.dll, the chances of it actually breaking anyone are close to zero, and the workaround if it does is to simply replace usage of it with default.

cc: @jkotas, @benaadams

The _value field wasn't previously readonly, because method calls were made on the ValueTask, resulting in a copy.  But now that ValueTask is a readonly struct, the field can be readonly, and these structs can then also be readonly.
It was superfluous and made sharing the code with corefx more challenging due to the netstandard1.0 build of System.Threading.Tasks.Extensions in corefx.
@stephentoub
Copy link
Member Author

@dotnet-bot test this please (most legs didn't start)

@stephentoub
Copy link
Member Author

@dotnet/dnceng, is there an issue with legs getting started in coreclr?

@mmitche
Copy link
Member

mmitche commented Jan 30, 2018

@stephentoub I think so...investigating.

@mmitche
Copy link
Member

mmitche commented Jan 30, 2018

@dotnet-bot test this please


private bool IsTaskCompletedSuccessfully => _task.IsCompletedSuccessfully;

private Task<TResult> GetTaskForResult() => AsyncTaskMethodBuilder<TResult>.GetTaskForResult(_result);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these extra layers going to regress perf? Note that the JIT is not great at inlining a complex generic constructs like these.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check.

Copy link
Member Author

@stephentoub stephentoub Jan 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it ends up being a problem, I expect the best recourse would be to just ifdef it. Is there a compilation constant we use for this kind of thing? #if CORECLR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be using #if netstandard for the less efficient portable version since the portable version is the odd one. Everything else will want to use the more efficient version - CORECLR, CORERT, MONO.

{
readonly partial struct ValueTask<TResult>
{
private static void ThrowNullTaskException() => ThrowHelper.ThrowArgumentNullException(ExceptionArgument.task);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to have add ThrowHelper to the CoreFX package instead so that a copy of this method is not stamped into each ValueTask instantiaion.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an issue for that, or anyone working on it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think so.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll open an issue. In the meantime I can just use ifdefs if you prefer.

Copy link
Member

@jkotas jkotas Jan 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand why you would not want to just do it as part this set of changes ... it just requires extra change in your CoreFX PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about corert?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to internal non-generic static class in meantime?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, were you suggesting adding a ThrowHelper to corefx rather than moving coreclr's implementation to shared? I thought you were suggesting moving it to shared. If you're just talking about a simple equivalent in corefx, sure, that's easy.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I am just talking about a simple local equivalent for ValueTuple in corefx. I do not think sharing ThrowHelper.cs makes sense.

@@ -74,7 +74,11 @@ internal ConfiguredValueTaskAwaiter(ValueTask<TResult> value, bool continueOnCap

/// <summary>Gets the task underlying the incomplete <see cref="_value"/>.</summary>
/// <remarks>This method is used when awaiting and IsCompleted returned false; thus we expect the value task to be wrapping a non-null task.</remarks>
(Task task, bool continueOnCapturedContext) IConfiguredValueTaskAwaiter.GetTask() => (_value.AsTaskExpectNonNull(), _continueOnCapturedContext);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the change to not use ValueTuple here. It will improve .NET Core as well.

ValueTuples are pretty expensive types with large footprint, unfortunately. Not as bad as Linq, but bad enough.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes me sad

@stephentoub
Copy link
Member Author

@dotnet-bot test Tizen armel Cross Checked Innerloop Build and Test please

@stephentoub stephentoub merged commit 0099e62 into dotnet:master Jan 30, 2018
@stephentoub stephentoub deleted the valuetaskshared branch January 30, 2018 22:47
dotnet-bot pushed a commit to dotnet/corert that referenced this pull request Jan 30, 2018
Several updates to ValueTask

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
jkotas pushed a commit to dotnet/corert that referenced this pull request Jan 31, 2018
Several updates to ValueTask

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
dotnet-bot pushed a commit to dotnet/corefx that referenced this pull request Jan 31, 2018
Several updates to ValueTask

Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
jkotas pushed a commit to dotnet/corefx that referenced this pull request Feb 1, 2018
Several updates to ValueTask

Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants